# _*_ coding:utf-8 _*_
from PyQt5.QtWidgets import QApplication, QMainWindow
from PyQt5 import QtGui, QtWidgets
from PyQt5.QtCore import QTimer
from Ui_main import Ui_MainWindow
from common.const import const
from tongsuopy.crypto import serialization,hashes,utils
from tongsuopy.crypto.asymciphers import ec

import os
import sys
import binascii
import base64
import time
import codecs
import ctypes
import icon_rc
import hashlib
import rsa


class MyMainWindow(QMainWindow):
    def __init__(self, parent=None):
        super(MyMainWindow, self).__init__(parent)
        self.ui = Ui_MainWindow()
        self.ui.setupUi(self)
        icon = QtGui.QIcon()
        icon.addPixmap(QtGui.QPixmap(":/icons/tools.png"), QtGui.QIcon.Normal, QtGui.QIcon.Off)
        self.setWindowIcon(icon)
        self.timer = QTimer()
        self.timer.setInterval(1000)
        self.timer.start()

        self.timer.timeout.connect(self.onTimerOut)

    def onTimerOut(self):        
        self.ui.lcdNumber.display(time.strftime("%Y-%m-%d %H:%M:%S"))

    def chooseFile(self):
        self.ui.statusbar.showMessage("")
        fileName, fileType = QtWidgets.QFileDialog.getOpenFileName(self, "选取文件", os.getcwd(), "All Files(*);;Text Files(*.txt)")
        if fileName != '' :
            with open(fileName, 'rb') as f:
                data = f.read()
                self.ui.data.setPlainText(data.hex().upper())
                self.ui.data_type_2.setChecked(True)
                self.ui.ret.setPlainText('')
                self.ui.statusbar.showMessage("自动转为Hex")

    def changeAction(self):
        self.ui.statusbar.showMessage("")
        data = self.ui.data.toPlainText()
        if self.ui.data_type_0.isChecked():
            if self.ui.ret_type_0.isChecked():
                pass
            if self.ui.ret_type_1.isChecked():
                '''ASCII-->Base64'''
                data = str(base64.b64encode(data.encode("utf-8")), 'utf-8')
            if self.ui.ret_type_2.isChecked():
                '''ASCII-->HEX'''
                data = binascii.hexlify(data.encode(encoding="utf-8")).decode().upper()
        
        if self.ui.data_type_1.isChecked():
            try:
                data_b64 = base64.b64decode(data)
            except ValueError:
                self.ui.statusbar.showMessage("原文Base64格式不合法。")
                return
            if self.ui.ret_type_0.isChecked():
                '''Base64-->ASCII'''
                try:
                    data = str(data_b64, 'utf-8')
                except UnicodeDecodeError:
                    self.ui.statusbar.showMessage("ASCII编码为不可见字符，请转换为Hex方便查看。")
                    self.ui.ret.setPlainText("")
                    return

            if self.ui.ret_type_1.isChecked():
                pass
            if self.ui.ret_type_2.isChecked():
                '''Base64-->HEX'''
                data = str(binascii.hexlify(data_b64), 'utf-8').upper()

        
        if self.ui.data_type_2.isChecked():
            try:
                hex = binascii.unhexlify(data)
            except ValueError:
                self.ui.statusbar.showMessage("原文Hex格式不合法")
                return

            if self.ui.ret_type_0.isChecked():
                '''HEX-->ASCII'''
                try:
                    data = str(hex, 'utf-8')
                except UnicodeDecodeError:
                    self.ui.statusbar.showMessage("ASCII编码为不可见字符，请转换为B64方便查看。")
                    self.ui.ret.setPlainText("")
                    return
            if self.ui.ret_type_1.isChecked():
                '''HEX-->Base64'''
                data = str(base64.b64encode(hex), 'utf-8')
            if self.ui.ret_type_2.isChecked():
                pass
        
        self.ui.ret.setPlainText(data)

    def dataChange(self):
        self.ui.statusbar.showMessage("")
        data = self.ui.data.toPlainText()
        self.ui.data_len.setText(f'{len(data)}')
    
    def retChange(self):
        self.ui.statusbar.showMessage("")
        ret = self.ui.ret.toPlainText()
        self.ui.ret_len.setText(f'{len(ret)}')

    def copyRet(self):
        self.ui.statusbar.showMessage("")
        clipboard = QApplication.clipboard()
        clipboard.setText(self.ui.ret.toPlainText())
        self.ui.statusbar.showMessage("复制成功")

    def hash(self, str):
        self.ui.statusbar.showMessage("")
        data = self.ui.hash_data.toPlainText()
        if data == "":
            return
        
        if self.ui.hash_data_asc.isChecked():
            hash_data = data.encode()
        if self.ui.hash_data_b64.isChecked():
            try:
                hash_data = base64.b64decode(data)
            except ValueError:
                self.ui.statusbar.showMessage("B64格式不合法")
                return
        if self.ui.hash_data_hex.isChecked():
            try:
                hash_data = binascii.unhexlify(data)
            except ValueError:
                self.ui.statusbar.showMessage("Hex格式不合法")
                return
        if str == const.MD5:
            ret = hashlib.md5(hash_data).hexdigest()       
        if str == const.SHA1:
            ret = hashlib.sha1(hash_data).hexdigest()
        if str == const.SHA224:
            ret = hashlib.sha224(hash_data).hexdigest()
        if str == const.SHA256:
            ret = hashlib.sha256(hash_data).hexdigest()
        if str == const.SHA384:
            ret = hashlib.sha384(hash_data).hexdigest()
        if str == const.SHA512:
            ret = hashlib.sha512(hash_data).hexdigest()
        if str == const.SM3:
            h = hashes.Hash(hashes.SM3())
            h.update(hash_data)
            ret = h.finalize()
        self.ui.hash_data.setPlainText(ret.upper())

    def genKey(self):
        self.ui.statusbar.showMessage("")
        tabIndex = self.ui.tabWidget.currentIndex()
        if tabIndex == 0:
            ''' RSA '''
            exp = self.ui.rsa_exp.currentText()
            mode = self.ui.rsa_mode.currentText()
            pk, sk = rsa.newkeys(int(mode), exponent=int(exp))
            if self.ui.key_type_b64.isChecked():
                self.ui.rsa_pk.setPlainText(str(base64.b64encode(pk.save_pkcs1('DER')), "utf-8"))
                self.ui.rsa_sk.setPlainText(str(base64.b64encode(sk.save_pkcs1('DER')), "utf-8"))
            if self.ui.key_type_hex.isChecked():
                self.ui.rsa_pk.setPlainText(str(binascii.hexlify(pk.save_pkcs1('DER')), "utf-8").upper())
                self.ui.rsa_sk.setPlainText(str(binascii.hexlify(sk.save_pkcs1('DER')), "utf-8").upper())
            if self.ui.key_type_pem.isChecked():
                self.ui.rsa_pk.setPlainText(str(pk.save_pkcs1('PEM'), "utf-8"))
                self.ui.rsa_sk.setPlainText(str(sk.save_pkcs1('PEM'), "utf-8"))
        
        if tabIndex == 1:
            ''' SM2 '''
            sk = self.ui.sm2_sk.toPlainText()
            if sk != "":
                if self.ui.key_type_b64.isChecked():
                    try:
                        sk = base64.b64decode(sk)
                        key = ec.derive_private_key(int(sk, 16), ec.SM2())
                        pk = key.public_key().public_numbers()
                        self.ui.sm2_pk_x.setPlainText(str(base64.b64encode(utils.int_to_bytes(pk.x)), "utf-8"))
                        self.ui.sm2_pk_y.setPlainText(str(base64.b64encode(utils.int_to_bytes(pk.y)), "utf-8"))
                    except ValueError:
                        self.ui.statusbar.showMessage("Base64格式不合法。")
                        return
                if self.ui.key_type_hex.isChecked():
                    try:
                        sk = binascii.unhexlify(sk)
                        key = ec.derive_private_key(int(sk, 16), ec.SM2())
                        pk = key.public_key().public_numbers()
                        self.ui.sm2_pk_x.setPlainText(str(utils.int_to_bytes(pk.x), "utf-8"))
                        self.ui.sm2_pk_y.setPlainText(str(utils.int_to_bytes(pk.x), "utf-8"))
                    except ValueError:
                        self.ui.statusbar.showMessage("Hex格式不合法。")
                        return
                if self.ui.key_type_pem.isChecked():
                    self.ui.statusbar.showMessage("暂不支持PEM格式密钥")
                    return
            else:
                key = ec.generate_private_key(ec.SM2())
                pubkey = key.public_key().public_numbers()
                prikey = utils.int_to_bytes(key.private_numbers().private_value)
                pkx = utils.int_to_bytes(pk.x)
                pky = utils.int_to_bytes(pk.y)
                if self.ui.key_type_b64.isChecked():
                    self.ui.sm2_pk_x.setPlainText(str(base64.b64encode(pkx), "utf-8"))
                    self.ui.sm2_pk_y.setPlainText(str(base64.b64encode(pky), "utf-8"))
                    self.ui.sm2_sk.setPlainText(str(base64.b64encode(prikey), "utf-8"))
                if self.ui.key_type_hex.isChecked():
                    self.ui.sm2_pk_x.setPlainText(pkx.upper())
                    self.ui.sm2_pk_y.setPlainText(pky.upper())
                    self.ui.sm2_sk.setPlainText(prikey.upper())
                if self.ui.key_type_pem.isChecked():
                    self.ui.statusbar.showMessage("暂不支持PEM格式密钥")
                    return

    def dataEnc(self):
        self.ui.statusbar.showMessage("")
        tabIndex = self.ui.tabWidget.currentIndex()
        if tabIndex == 0:
            ''' RSA '''
            rsaPk = self.ui.rsa_pk.toPlainText()
            if rsaPk == "":
                self.ui.statusbar.showMessage("加密时公钥不能为空。")
                return
            data = self.ui.rsa_data.toPlainText()
            if data == "":
                return

            if self.ui.key_type_b64.isChecked():
                try:
                    pk = base64.b64decode(rsaPk)
                    crypto = rsa.encrypt(binascii.unhexlify(data), rsa.PublicKey.load_pkcs1(pk, format='DER'))
                    self.ui.rsa_ret.setPlainText(str(binascii.hexlify(crypto), "utf-8").upper())
                except ValueError:
                    self.ui.statusbar.showMessage("Base64格式不合法。")
                    return
            if self.ui.key_type_hex.isChecked():
                try:
                    pk = binascii.unhexlify(rsaPk)
                    crypto = rsa.encrypt(binascii.unhexlify(data), rsa.PublicKey.load_pkcs1(pk, format='DER'))
                    self.ui.rsa_ret.setPlainText(str(binascii.hexlify(crypto), "utf-8").upper())
                except ValueError:
                    self.ui.statusbar.showMessage("Hex格式不合法。")
                    return
            if self.ui.key_type_pem.isChecked():
                try:
                    crypto = rsa.encrypt(binascii.unhexlify(data), rsa.PublicKey.load_pkcs1(rsaPk, format='PEM'))
                    self.ui.rsa_ret.setPlainText(str(binascii.hexlify(crypto), "utf-8").upper())
                except:
                    self.ui.statusbar.showMessage("PEM格式不合法。")
                    return
        
        if tabIndex == 1:
            ''' SM2 '''
            pk = self.ui.sm2_pk_x.toPlainText()
            if pk == "":
                self.ui.statusbar.showMessage("加密时公钥不能为空。")
                return
            # sk = self.ui.sm2_sk.toPlainText()
            # if sk == "":
            #     self.ui.statusbar.showMessage("加密时密钥不能为空。")
            #     return
            data = self.ui.sm2_data.toPlainText()
            if data == "":
                self.ui.statusbar.showMessage("加密时数据不能为空。")
                return
            try:
                data = binascii.unhexlify(data)
            except ValueError:
                self.ui.statusbar.showMessage("加密数据需为Hex格式。")
                return
            if self.ui.key_type_b64.isChecked():
                pkx = base64.b64decode(pk)
                if len(pkx) <= 64:
                    pky = self.ui.sm2_pk_y.toPlainText()
                    if pky == "":
                        return
                    #pkx += base64.b64decode(pky)
                # sk = base64.b64decode(sk)
                pubkey = ec.EllipticCurvePublicNumbers(int(pkx, 16), int(pky, 16), ec.SM2())
                enc_data = pubkey.public_key().encrypt(data)
                #sm2_crypt = sm2.CryptSM2(private_key=None, public_key=str(binascii.hexlify(pkx), "utf-8"))
                #print(binascii.hexlify(pkx))
                #enc_data = sm2_crypt.encrypt(data)
                self.ui.sm2_ret.setPlainText(str(binascii.hexlify(enc_data), "utf-8").upper())
            if self.ui.key_type_hex.isChecked():
                if len(pk) <= 64:
                    pky = self.ui.sm2_pk_y.toPlainText()
                    if pky == "":
                        return
                    #pk += pky
                pubkey = ec.EllipticCurvePublicNumbers(int(pkx, 16), int(pky, 16), ec.SM2())
                enc_data = pubkey.public_key().encrypt(data)
                #sm2_crypt = sm2.CryptSM2(private_key=None, public_key=pk)
                #enc_data = sm2_crypt.encrypt(data)
                self.ui.sm2_ret.setPlainText(str(binascii.hexlify(enc_data), "utf-8").upper())
            if self.ui.key_type_pem.isChecked():
                self.ui.statusbar.showMessage("暂不支持导出PEM格式密钥")
                return
    def dataDec(self):
        self.ui.statusbar.showMessage("")
        tabIndex = self.ui.tabWidget.currentIndex()
        if tabIndex == 0:
            ''' RSA '''
            rsaSk = self.ui.rsa_sk.toPlainText()
            if rsaSk == "":
                self.ui.statusbar.showMessage("解密时私钥不能为空。")
                return
            data = self.ui.rsa_data.toPlainText()
            if data == "":
                return

            if self.ui.key_type_b64.isChecked():
                try:
                    sk = base64.b64decode(rsaSk)
                    crypto = rsa.decrypt(binascii.unhexlify(data), rsa.PrivateKey.load_pkcs1(sk, format='DER'))
                    self.ui.rsa_ret.setPlainText(str(binascii.hexlify(crypto), "utf-8").upper())
                except ValueError:
                    self.ui.statusbar.showMessage("Base64格式不合法。")
                    return
            if self.ui.key_type_hex.isChecked():
                try:
                    sk = binascii.unhexlify(rsaSk)
                    crypto = rsa.decrypt(binascii.unhexlify(data), rsa.PrivateKey.load_pkcs1(sk, format='DER'))
                    self.ui.rsa_ret.setPlainText(str(binascii.hexlify(crypto), "utf-8").upper())
                except ValueError:
                    self.ui.statusbar.showMessage("Hex格式不合法。")
                    return
            if self.ui.key_type_pem.isChecked():
                try:
                    crypto = rsa.decrypt(binascii.unhexlify(data), rsa.PrivateKey.load_pkcs1(rsaSk, format='PEM'))
                    self.ui.rsa_ret.setPlainText(str(binascii.hexlify(crypto), "utf-8").upper())
                except:
                    self.ui.statusbar.showMessage("PEM格式不合法。")
                    return
        
        if tabIndex == 1:
            ''' SM2 '''
            sk = self.ui.sm2_sk.toPlainText()
            if sk == "":
                self.ui.statusbar.showMessage("解密时私钥不能为空。")
                return
            data = self.ui.sm2_data.toPlainText()
            if data == "":
                return
            try:
                data = binascii.unhexlify(data)
            except ValueError:
                self.ui.statusbar.showMessage("解密数据需为Hex格式。")
                return
            if self.ui.key_type_b64.isChecked():
                sk = base64.b64decode(sk)
                key = ec.EllipticCurvePrivateNumbers(int(sk, 16), None).private_key()
                dec_data = key.decrypt(data)
                #sm2_crypt = sm2.CryptSM2(private_key=str(binascii.hexlify(sk), "utf-8"), public_key=None)
                #dec_data = sm2_crypt.decrypt(data)
                self.ui.sm2_ret.setPlainText(str(binascii.hexlify(dec_data), "utf-8").upper())
            if self.ui.key_type_hex.isChecked():
                key = ec.EllipticCurvePrivateNumbers(int(sk, 16), None).private_key()
                dec_data = key.decrypt(data)
                #sm2_crypt = sm2.CryptSM2(private_key=sk, public_key=None)
                #dec_data = sm2_crypt.decrypt(data)
                self.ui.sm2_ret.setPlainText(str(binascii.hexlify(dec_data), "utf-8").upper())
            if self.ui.key_type_pem.isChecked():
                self.ui.statusbar.showMessage("暂不支持PEM格式密钥")
                return


if __name__ == "__main__":

    try:
        ctypes.windll.shell32.SetCurrentProcessExplicitAppUserModelID("Francois")
        app = QApplication(sys.argv)
        myWin = MyMainWindow()
        myWin.show()
        sys.exit(app.exec_())
    except:
        pass